package com.atguigu.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.model.system.SysUser;
import com.atguigu.model.vo.LoginVo;
import com.atguigu.model.vo.RouterVo;
import com.atguigu.model.vo.SysUserQueryVo;
import com.atguigu.springsecurity.coutom.LoginUser;


import com.atguigu.springsecurity.service.LoginLogService;
import com.atguigu.system.exception.GuiguException;
import com.atguigu.system.mapper.SysUserMapper;
import com.atguigu.system.service.SysMenuService;
import com.atguigu.system.service.SysUserService;
import com.atguigu.system.utils.IpUtil;
import com.atguigu.system.utils.JwtHelper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author lemon
 * @since 2023-01-22
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Resource
    private SysMenuService sysMenuService;

    @Resource
    private AuthenticationManager authenticationManager;


    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private LoginLogService loginLogService;

    /**
     * 获取分页列表
     *
     * @param pageParam
     * @param userQueryVo
     * @return
     */
    @Override
    public IPage<SysUser> selectPage(Page<SysUser> pageParam, SysUserQueryVo userQueryVo) {

        LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        String keyword = userQueryVo.getKeyword();

        if (!StringUtils.isEmpty(keyword)) {
            lambdaQueryWrapper.and(obj -> {
                obj.eq(SysUser::getPhone, keyword).or().like(SysUser::getName, keyword);
            });
        }

        String createTimeBegin = userQueryVo.getCreateTimeBegin();
        if (!StringUtils.isEmpty(createTimeBegin)) {

            lambdaQueryWrapper.ge(SysUser::getCreateTime, createTimeBegin);
        }

        String createTimeEnd = userQueryVo.getCreateTimeEnd();
        if (!StringUtils.isEmpty(createTimeEnd)) {
            lambdaQueryWrapper.le(SysUser::getCreateTime, createTimeEnd);
        }

        lambdaQueryWrapper.orderByDesc(SysUser::getCreateTime);
        Page<SysUser> page = page(pageParam, lambdaQueryWrapper);
        return page;

    }

    /**
     * 更新状态
     *
     * @param id
     * @param status
     */
    @Override
    public void updateStatus(Long id, Integer status) {
        SysUser sysUser = getById(id);
        sysUser.setStatus(status);
        updateById(sysUser);
    }

    /**
     * 保存用户
     *
     * @param user
     */
    @Override
    public void saveUser(SysUser user) {
        // 还要判断一下这个用户名是否重复
        LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysUser::getUsername, user.getName());
        int count = count(lambdaQueryWrapper);
        if (count > 0) {
            throw new GuiguException(201, "用户存已存在");
        }
        // 方法内部融合了盐值
//        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode(user.getPassword());
        user.setPassword(encode);

        save(user);


    }

    /**
     * 进行登录
     *
     * @param loginVo
     * @return
     */
    @Override
    public String login(LoginVo loginVo, HttpServletRequest request) {
        // 将用户输入的用户名和面封装成了authentication
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
        // (将UserDetailServiceImpl里面查询到的user放置在里面 框架内部就会帮助我们将loginUserVo设置进去)
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        // 如果认证通过了， 使用userId生成jwt  jwt存入ResponseResult并且返回
        LoginUser principal = (LoginUser) authenticate.getPrincipal();

        String userId = principal.getSysUser().getId();
        String username = principal.getUsername();
        // 生成token
        String token = JwtHelper.createToken(userId, username);
        // 把用户完整信息存入redis， userId作为key
        String jsonString = JSON.toJSONString(principal);
        stringRedisTemplate.opsForValue().set("login:" + userId, jsonString, 30, TimeUnit.MINUTES);
//        redisCache.setCacheObject("login:" + userId.toString(), principal);
        System.out.println(token);

        // TODO 记录登录日志
        loginLogService.recordLoginLog(username, 1, IpUtil.getIpAddress(request), "登录成功");

        return token;
    }

    /**
     * 用户信息接口
     *
     * @param request
     * @return
     */
    @Override
    public Map<String, Object> info(HttpServletRequest request) {
        // 得到token字符串
        String token = request.getHeader("token");

        // 用户名
        String username = JwtHelper.getUsername(token);
        LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysUser::getUsername, username);
        // 得到用户id
        SysUser sysUser = getOne(lambdaQueryWrapper);


        Map<String, Object> result = new HashMap<>();

        result.put("name", username);
        result.put("avatar", "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
        result.put("roles", "admin");

        // 菜单的权限数据
        List<RouterVo> routerVoList = sysMenuService.getUerMenuList(sysUser.getId());
        result.put("routers", routerVoList);

        // 按钮权限数据
        // 根据用户id获取用户按钮权限
        List<String> permsList = sysMenuService.findUserPermsList(sysUser.getId());
        result.put("buttons", permsList);
        return result;
    }

    /**
     * @param userName
     * @return
     */
    @Override
    public SysUser getUserInfoByUserName(String userName) {
        LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysUser::getUsername, userName);
        return getOne(lambdaQueryWrapper);
    }

    /**
     * 登出
     */
    @Override
    public void logout() {
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        String principal = (String) authentication.getPrincipal();
        // 我们需要得到字符串后，
        LoginUser loginUser = JSON.parseObject(principal, LoginUser.class);
        String key = "login:";
        String userId = loginUser.getSysUser().getId();
        key = key + userId;
        // 删除redis里面的值就可以了
        stringRedisTemplate.delete(key);
    }
}
